home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
Libraries
/
Sherlock 2.0
/
DevLibSrc
/
Mac DevLib
/
mac_gui.c
< prev
next >
Wrap
Text File
|
1995-11-03
|
40KB
|
1,769 lines
/*
devlib: Macintosh GUI routines that handle windows, dialogs and menus.
Note: The w_arg_dialog routine gets Sherlock arguments,
and depends on resource numbers for the Sherlock argument dialog.
We want the log window to be asynchronous, i.e., we want to
send output to it at any time, even if it is not active and even if
parts of it are covered by other windows.
Writing is done immediately, without waiting for an update event.
This keeps the log window as current as possible.
No TextEdit routines are used so as to maximize speed.
Scrolling the window is not supported.
Except as noted, Sherlock macros may be used anywhere in this file.
source: mac_gui.c
started:
October 26, 1995
Changes made to support new Universal Headers.
November 4, 1993.
*/
/* Version:
Septermber 25, 1995.
Changes made for CodeWarrior.
#define Boolean int
April 13,1994.
Localized variables and converted to new-style function headers.
January 7, 1994.
Removed #include of sherlock header file.
Renamed several routines.
w_std_file_dialog and w_arg_dialog were made local to this file.
*/
/* Includes. */
/* Macintosh includes. */
#include <Controls.h>
#include <Desk.h>
#include <Dialogs.h>
#include <Errors.h>
#include <Events.h>
#include <Files.h>
#include <Fonts.h>
#include <OSEvents.h>
#include <OSUtils.h>
#include <Quickdraw.h>
#include <Memory.h>
#include <Menus.h>
#include <Packages.h>
#include <Resources.h>
#include <SegLoad.h>
#include <ToolUtils.h>
#include <Windows.h>
#include <LIBlib.h>
#include <LIBlog.h>
#include <mac_gui.h>
#ifdef __MWERKS__
#define Boolean int
#define CtoPstr c2pstr
#define PtoCstr p2cstr
#include <Strings.h>
#include <StandardFile.h>
#endif
/* Make sure we call the REAL Macintosh ToolBox routines in this file. */
#undef DrawMenuBar
#undef GetNextEvent
#undef MenuSelect
#undef WaitNextEvent
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef THINK_C
#include <pascal.h>
#else
#include <Strings.h> /* MPW only */
#endif
#ifdef THINK_C
// From <LoMem.h>: Warning: can't be used on a Power Mac.
// #include <LoMem.h>
#define Declare_LoMem(type, name, address) type (name) : (address)
Declare_LoMem(THz, ApplZone, 0x2AA);
#endif
/* About hidden and explicit entry points.
Several Toolbox routines are redefined via macros in sl.h to call
"hidden entry point" functions in this module. The macros that
redefine the Toolbox routines must not be active in this file!!
Toolbox Function Hidden Entry Point Function
DrawMenuBar w_drawMenuBar
GetNextEvent w_event
MenuSelect w_menuSelect
WaitNextEvent w_event
Explicit entry points Called by
w_applEvent directly
w_mac_init directly
w_arg_dialog directly
w_std_file_dialog directly
w_init from all other entry points
slw_write log_cout
slw_update directly
Coding conventions:
Each entry point, hidden or not, must preserve the GrafPort
or the application will crash.
Local routines need not preserve the GrafPort because the entry points do so.
Each entry point (or its continuation in the case of sl_wCout) calls
w_init if necessary before using any variable defined in this file.
This is a defensive measure so the code in this file will not crash
if the application calls one of the hidden entry points before calling
SL_INIT.
WARNING: SetPort(w_wp) must be done *after* calling w_init
because w_init itself preserves the GrafPort.
*/
/* Constants.
Change these constants if you change the resource ID's in the dialog
named "Sherlock Dialog" in the file called Sherlock Resources.
*/
#define SHERLOCK_DIALOG_ID 206 /* Resource ID of dialog. */
#define OK_ITEM 1 /* Dialog Item Numbers... */
#define CANCEL_ITEM 2
#define TO_DISK_FILE_ITEM 3
#define SHERLOCK_ARGS_ITEM 5
/*
Constants for menu handling.
The values of these items correspond to the order of code in w_drawMenuBar.
MBarHeight is a low memory global, whose value is usually 20.
*/
#ifndef THINK_C /* Think C defines MBarHeight to be a low-memory global. */
#define MBarHeight 20
#endif
#define APPLE_MENU_ID 128 /* Resource ID's for menus... */
#define FILE_MENU_ID 129
#define EDIT_MENU_ID 130
#define QUIT_ITEM 1 /* File menu. */
#define W_OPTIONS_ITEM 1 /* Sherlock menu... */
/* Item 2 is a dimmed line */
#define W_STATS_ITEM 3
#define W_STATS2_ITEM 4
#define W_CLEAR_ITEM 5
/* Item 6 is a dimmed line */
#define W_FILE_ITEM 7
#define W_WINDOW_ITEM 8
/* Item 9 is a dimmed line */
#define W_STACK_ITEM 10
#define W_DUMP_ITEM 11
#define W_DUMP2_ITEM 12
#define W_DUMP3_ITEM 13
/* Prototypes of internal routines. */
static void w_abort (int beeps);
static void w_arg_dialog
(char * on_string, char * off_string,
char * fileNamePrompt, char * defaultFileName);
static void w_activate (Boolean active_flag);
static Boolean w_command (long where);
static Boolean w_commandStd (long where);
static void w_content (void);
static void w_drag (Point global_pt);
static void w_goAway (Point global_pt);
static void w_grow (Point global_pt);
static void w_hide (void);
static void w_hiliteButton (DialogPtr dp);
static void w_init (Boolean openFlag, char * windowName);
static Boolean w_key (EventRecord * event);
static void w_line_insert (char * buffer, int count);
static void w_line_out (void);
static void w_line_update (void);
static void w_pStr (char * s);
static Boolean w_rawDialog
(short * vRefNum, char * fileName, int max_fileName,
char * fileNamePrompt, char * defaultFileName);
static void w_scrollWindow (void);
static int w_std_file_dialog
(short * vRefNum, char * fileName, int max_fileName,
char * fileNamePrompt, char * defaultFileName);
static void w_setupWindow (void);
static void w_show (void);
static void w_zoom (Point global_pt, int zoomCode);
/* Local vars. */
/* w_mac_init: Output control flags. */
static Boolean w_windowFlag = TRUE; /* TRUE: output to window. */
static void (*w_aboutCallBack)(void) = 0L; /* "about" callback routine. */
static void (*w_eventCallBack)(void) = 0L; /* event callback routine. */
static void (*w_dumpCallBack)(void) = 0L; /* user dump callback routine. */
static void (*w_dump2CallBack)(void) = 0L; /* user dump callback routine. */
static void (*w_dump3CallBack)(void) = 0L; /* user dump callback routine. */
/* w_mac_init: Menu initialization values. */
static Boolean w_aboutFlag = FALSE; /* TRUE: add about item. */
static Boolean w_stdMenuFlag = FALSE; /* TRUE: add standard menus. */
static Boolean w_slMenuFlag = FALSE; /* TRUE: add sherlock menu. */
static pstring w_aboutTitle = "\p"; /* Name of "about" menu item. */
static pstring w_userItem1 = "\p"; /* Title of first user item. */
static pstring w_userItem2 = "\p"; /* Title of second user item. */
static pstring w_userItem3 = "\p"; /* Title of third user item. */
/* Internal state flags. */
static int w_eventSkipCount = 0; /* w_applEvent skip count. */
static Boolean w_toolBoxFlag = FALSE; /* TRUE: Mac ToolBox inited. */
static Boolean w_wInitFlag = FALSE; /* TRUE: w_init inited. */
static Boolean w_MBarFlag = FALSE; /* TRUE: menu bar inited. */
static Boolean w_activeFlag = FALSE; /* TRUE: window active. */
static Boolean w_showFlag = TRUE; /* TRUE: window is showing. */
/* The circular line buffer. */
/*
This buffer hold the last MAX_SLOTS lines and is used to
refresh the log window during update events.
The code will work regardless of the value of MAX_SLOTS, but
MAX_SLOTS should be chosen so that it is greater than the number
of lines in the log window.
All entries in the buffer are MAX_LINE_CHARS long, which makes
replacing one line by another easy.
*/
#define MAX_SLOTS 30
#define MAX_LINE_CHARS 120
#define MAX_WBUF (MAX_SLOTS * MAX_LINE_CHARS)
static char * w_wBuf = NULL; /* Character buffer. */
static int * w_wCount = NULL; /* Line counts. */
static int w_wSlot = -1; /* Current wBuf slot. */
static int w_wIndex = -MAX_LINE_CHARS; /* Current wBuf index. */
static int w_wLines = 0; /* Current line count. */
static int w_wMaxLines = 0; /* Window size in lines. */
/* Descriptions of the current font and screen layout. */
#define LEFT_OFFSET 4 /* Left Margin. */
#define TOP_CLIP 4 /* Should be >= 0. */
#define RIGHT_CLIP 4 /* Should be at least 1. */
#define BOTTOM_CLIP 4 /* Should be at least 1. */
#define SBarWidth 15 /* Width of scroll bars. */
#define EXTRA_LEADING 1 /* Can be zero. */
static int w_height = 0; /* Distance above baseline. */
static int w_dy = 0; /* Distance between lines. */
static int w_y0 = 0; /* Offset of first line. */
static int w_maxRow = MAX_SLOTS; /* Writable verticle pixels. */
static int w_curRow = 0; /* Current row number. */
static int w_MBarHeight = 20; /* Height of menu bar. */
/* Buffers used to accumulate Sherlock arguments. */
#define MAX_ARGS 50
#define MAX_COMMAND 500
static int w_argc = 1;
static char* w_argv[MAX_ARGS]; /* Command line buffers. */
static unsigned char w_comBuf[MAX_COMMAND];
/* Window and menu vars. */
static WindowPtr w_wp = 0L;
static Rect w_boundsRect;
static Rect w_clipRect;
static Rect w_dragRect;
static Rect w_growRect;
static MenuHandle w_menuH = 0L;
static MenuHandle w_appleMenuH = 0L;
static MenuHandle w_fileMenuH = 0L;
static MenuHandle w_editMenuH = 0L;
static int w_sherlockID = -1;
/* w_abort
This routine is called if the log window can't be initialized.
Assume nothing is available that must be initialized.
*/
static void
w_abort(int beeps)
{
#if defined(THINK_C) || defined(__MWERKS__)
int i;
for (i = 0; i < beeps; i++) {
SysBeep(20);
}
abort();
#else
abort();
#endif
}
/* w_activate: handle an activate event.
Set w_activeFlag as appropriate.
Events are handled in the log window only if w_activeFlag is TRUE.
*/
static void
w_activate(Boolean active_flag)
{
/* Remember the state of the log window. */
w_activeFlag = active_flag;
/* Never wait for an update event. */
if (active_flag) {
slw_update();
}
}
/* w_applEvent: an explicit entry point.
This routine provides a minimal event-loop for an application.
Return FALSE if the application should quit.
WARNING: Do not call this routine if
o Your program uses the stdout output stream (putchar, printf, etc.)
-- or --
o Your program has another event loop.
*/
Boolean
w_applEvent(int eventSkipCount)
{
GrafPtr oldPort;
EventRecord applEvent;
Boolean return_value;
GetPort(&oldPort);
/* Initialize the log window if required. */
if (!w_wInitFlag) {
w_init(FALSE, "log");
}
SetPort(w_wp);
/* Execute this routine only once every eventSkipCount calls. */
if (eventSkipCount > 0 && w_eventSkipCount++ < eventSkipCount) {
goto true_ret;
}
else {
/* Start counting up again. */
w_eventSkipCount = 0;
}
/* Get the event using w_event. Return TRUE if there is none. */
/* Calls to TEIdle and SystemTask are handled by w_event. */
if (!w_event(everyEvent, &applEvent, 0L, NULL, FALSE)) {
goto true_ret;
}
if (applEvent.what == nullEvent) {
goto true_ret;
}
switch (applEvent.what) {
case mouseDown:
{
WindowPtr applWindow;
switch (FindWindow(applEvent.where, &applWindow)) {
case inMenuBar:
if (w_MBarFlag && w_stdMenuFlag) {
return_value = w_commandStd(w_menuSelect(applEvent.where));
goto value_ret;
}
else {
/* Menu bar not installed. Ignore mouseDown events. */
goto true_ret;
}
case inSysWindow:
SystemClick(&applEvent, applWindow );
goto true_ret;
default:
goto true_ret;
}
}
case keyDown: case autoKey:
{
/* Do nothing if the menu bar has not been installed. */
char c = applEvent.message & charCodeMask;
if (w_MBarFlag && w_stdMenuFlag && (applEvent.modifiers & cmdKey) != 0) {
return_value = w_commandStd(MenuKey(c));
goto value_ret;
}
else {
goto true_ret;
}
}
case activateEvt: case updateEvt: default:
goto true_ret;
}
value_ret:
SetPort(oldPort);
return return_value;
true_ret:
SetPort(oldPort);
return TRUE;
}
/* w_arg_dialog: an explicit entry point.
Prompt the user for arguments and file name.
*/
static void
w_arg_dialog (
char * on_string,
char * off_string,
char * fileNamePrompt,
char * defaultFileName)
{
Boolean fileFlag;
GrafPtr oldPort;
short vRefNum;
char fileName[MAX_LOG_FILE_NAME];
GetPort(&oldPort);
/* Initialize the log window if required. */
if (!w_wInitFlag) {
w_init(FALSE, "log");
}
SetPort(w_wp);
/* Get arguments, including w_comBuf. */
fileFlag = w_rawDialog(&vRefNum, fileName, MAX_LOG_FILE_NAME,
fileNamePrompt, defaultFileName);
/* Parse the arguments entered from the dialog box. */
{
char c;
char * cp = (char *) &w_comBuf[0];
w_argc = 1;
while (w_argc < MAX_ARGS) {
while (isspace(*cp)) {
cp++;
}
if ( !*cp ) {
break;
}
/* Point w_argv[] at the start of the argument. */
w_argv[w_argc++] = cp++;
/* Scan past the argument and terminate the argument. */
while (*cp && !isspace(*cp)) {
cp++;
}
c = *cp;
*cp++ = '\0';
if (!c) {
break;
}
}
}
/* Initialize the Sherlock variables. */
#ifdef SHERLOCK /* 12/13/93 */
sl_parse(&w_argc, w_argv, on_string, off_string);
#endif
/* Open the requested file, if any. */
if (fileFlag && fileName[0] != '\0') {
log_open_vRefNum(vRefNum, fileName);
}
SetPort(oldPort);
}
/* w_command: handle Sherlock menu commands. Called from w_event().
Return FALSE if the user must take further action.
*/
static Boolean
w_command(long where)
{
int item = LoWord(where);
int menu = HiWord(where);
/* Return false if the Sherlock menu has not bee installed. */
if (w_sherlockID == -1 || menu != w_sherlockID) {
return FALSE;
}
switch(item) {
/* Item cases. */
case W_OPTIONS_ITEM:
/* Use simple ++ and -- for prefix here. */
w_arg_dialog("++", "--", lib_log_file_prompt, lib_log_file_name);
break;
case W_STATS_ITEM:
#ifdef SHERLOCK /* 12/13/93 */
sl_edump();
#endif
break;
case W_STATS2_ITEM:
#ifdef SHERLOCK /* 12/13/93 */
sl_dump();
#endif
break;
case W_CLEAR_ITEM:
#ifdef SHERLOCK /* 12/13/93 */
sl_clear();
#endif
break;
case W_FILE_ITEM:
if (log_isopen()) {
log_close();
}
else {
short vRefNum;
char fileName[MAX_LOG_FILE_NAME];
if(w_std_file_dialog(&vRefNum, fileName, MAX_LOG_FILE_NAME,
"Sherlock Tracing File...", "sl_trace")
) {
log_open_vRefNum(vRefNum, fileName);
}
}
break;
case W_WINDOW_ITEM:
if (w_showFlag) {
w_hide();
}
else {
w_show();
}
break;
case W_STACK_ITEM:
/* Stack walk-back */
#ifdef SHERLOCK /* 12/13/93 */
sl_dumpstk();
#endif
break;
case W_DUMP_ITEM:
/* Execute the user dump routine. */
if (w_dumpCallBack != 0L) {
(*w_dumpCallBack)();
}
break;
case W_DUMP2_ITEM:
/* Execute the user dump routine. */
if (w_dump2CallBack != 0L) {
(*w_dump2CallBack)();
}
break;
case W_DUMP3_ITEM:
/* Execute the user dump routine. */
if (w_dump3CallBack != 0L) {
(*w_dump3CallBack)();
}
break;
default: break;
}
HiliteMenu(0);
return TRUE;
}
/* w_commandStd: handle standard menu commands. Called from w_applEvent().
Return FALSE if the application should quit.
*/
static Boolean
w_commandStd(long where)
{
int item = LoWord(where);
int menu = HiWord(where);
/* Do nothing if the standard menu has not been installed. */
if (!w_stdMenuFlag || !w_MBarFlag) {
return TRUE;
}
switch(menu) {
case APPLE_MENU_ID:
if (item == 1 && w_aboutFlag) {
if (w_aboutCallBack != 0L) {
/* Execute the user's dialog routine. */
(*w_aboutCallBack)();
}
HiliteMenu(0);
return TRUE;
}
else {
/* Enable the edit menu. */
Str255 DAName;
EnableItem(w_editMenuH, 0);
GetItem(w_appleMenuH, item, DAName);
OpenDeskAcc(DAName);
DisableItem(w_editMenuH, 0);
HiliteMenu(0);
return TRUE;
}
case FILE_MENU_ID:
HiliteMenu(0);
if (item == QUIT_ITEM) {
return FALSE;
}
else {
return TRUE;
}
default:
HiliteMenu(0);
return TRUE;
}
}
/* w_content: handle a mouse down event in the content region of the log window. */
static void
w_content(void)
{
if (FrontWindow() != w_wp) {
SelectWindow(w_wp);
ShowCursor();
}
}
/* w_drag: Handle a mouse down event in the drag region of the log window. */
static void
w_drag(Point global_pt)
{
DragWindow(w_wp, global_pt, &w_dragRect );
}
/* w_drawMenuBar: a hidden entry point called by the DrawMenuBar macro.
This is also called by sl_applMenuInit().
Install the Sherlock menu as the last menu and
call the DrawMenuBar Toolbox routine.
*/
void
w_drawMenuBar(void)
{
GrafPtr oldPort;
/* Just call the Macintosh ToolBox DrawMenuBar if we have been inited. */
if (w_MBarFlag) {
DrawMenuBar();
return;
}
/* Save */
GetPort(&oldPort);
/* Initialize the log window if required. */
if (!w_wInitFlag) {
w_init(FALSE, "log");
}
SetPort(w_wp);
if (w_stdMenuFlag) {
/* Install the apple, file, and edit menus. */
/* Install the apple menu. */
w_appleMenuH = NewMenu(APPLE_MENU_ID, "\p\024");
/* Install the about item if present. */
if (w_aboutFlag && w_aboutTitle != 0L && w_aboutTitle[0] != 0) {
AppendMenu(w_appleMenuH, w_aboutTitle);
}
/* Install the list of Desk Accessories in the apple menu. */
AddResMenu(w_appleMenuH, 'DRVR' );
InsertMenu(w_appleMenuH, 0);
/* Insert a file menu containing only quit. */
w_fileMenuH = NewMenu(FILE_MENU_ID, "\pFile");
AppendMenu(w_fileMenuH, "\pQuit/Q");
InsertMenu(w_fileMenuH, 0);
/* Insert the standard, dimmed edit menu. */
w_editMenuH = NewMenu(EDIT_MENU_ID, "\pEdit");
AppendMenu(w_editMenuH, "\pUndo/Z");
AppendMenu(w_editMenuH, "\p(-");
AppendMenu(w_editMenuH, "\pCut/X");
AppendMenu(w_editMenuH, "\pCopy/C");
AppendMenu(w_editMenuH, "\pPaste/V");
InsertMenu(w_editMenuH, 0);
/* Dim the entire edit menu. */
DisableItem(w_editMenuH, 0);
/* Make sure we never mess with the menus again. */
w_MBarFlag = TRUE;
}
if (w_slMenuFlag) {
/* Install the Sherlock menu. */
/* Initialize the Sherlock menu information. */
int i = 0;
for (i = 128; i < 200; i++) {
if (GetMHandle(i) == 0L) {
w_sherlockID = i;
break;
}
}
/* Enter items into the Sherlock menu. */
w_menuH = NewMenu(w_sherlockID, "\pSherlock");
AppendMenu(w_menuH, "\pOptions...");
AppendMenu(w_menuH, "\p(-");
AppendMenu(w_menuH, "\pEnabled Stats");
AppendMenu(w_menuH, "\pAll Stats");
AppendMenu(w_menuH, "\pClear Stats");
AppendMenu(w_menuH, "\p(-");
if (log_isopen()) {
AppendMenu(w_menuH, "\pClose File");
}
else {
AppendMenu(w_menuH, "\pOpen File");
}
if (w_showFlag) {
AppendMenu(w_menuH, "\pClose Window");
}
else {
AppendMenu(w_menuH, "\pOpen Window");
}
AppendMenu(w_menuH, "\p(-");
AppendMenu(w_menuH, "\pCall Stack");
/* Install call back routines. */
if (w_dumpCallBack != 0L) {
AppendMenu(w_menuH, w_userItem1);
if (w_dump2CallBack != 0L) {
AppendMenu(w_menuH, w_userItem2);
if (w_dump3CallBack != 0L) {
AppendMenu(w_menuH, w_userItem3);
}
}
}
InsertMenu(w_menuH, 0);
/* Make sure we never mess with the menus again. */
w_MBarFlag = TRUE;
}
/* Call the real Toolbox routine. */
DrawMenuBar();
/* Restore */
SetPort(oldPort);
}
/* w_event: a hidden entry point called by GetNextEvent and WaitNextEvent macros.
The WaitNextEvent macro sets wait_flag to TRUE.
Call the GetNextEvent() or the WaitNextEvent Toolbox routine,
handle all events that pertain to the log window,
and pass all other events on to the caller.
Return TRUE if the event requires further action.
*/
Boolean
w_event(
int user_mask,
EventRecord * event,
long sleep,
RgnHandle mouseRgn,
Boolean wait_flag)
{
GrafPtr oldPort;
WindowPtr wp = NULL;
Boolean defaultReturn;
/* Save */
GetPort(&oldPort);
/* Initialize the log window if required. */
if (!w_wInitFlag) {
w_init(FALSE, "log");
}
SetPort(w_wp);
/* Get the next event, if any. */
/* Both these calls update the caller's event record. */
if (wait_flag) {
defaultReturn = WaitNextEvent(user_mask, event, sleep, mouseRgn);
}
else {
defaultReturn = GetNextEvent(user_mask, event);
}
if (event->what == nullEvent) {
goto true_ret;
}
switch (event -> what) {
case keyDown: case autoKey:
/* Handle keypressed events only if log window is active. */
if (!w_activeFlag) {
goto true_ret;
}
else if (w_key(event)) {
goto false_ret;
}
else {
goto true_ret;
}
case mouseUp: case nullEvent:
/* Let user handle these. */
goto true_ret;
case activateEvt:
if ( ((WindowPtr) event -> message) != w_wp) {
goto true_ret;
}
else {
w_activate(((event -> modifiers) & activeFlag) != 0);
goto false_ret;
}
case updateEvt:
if ( ((WindowPtr) event -> message) != w_wp) {
goto true_ret;
}
else {
slw_update();
goto false_ret;
}
case mouseDown:
{
int window_type = FindWindow(event->where, &wp);
switch (window_type) {
case inSysWindow:
/* User handles all desk accessories. */
goto true_ret;
case inMenuBar:
/* w_menuSelect will handle this later. */
goto true_ret;
case inContent:
/* Only handle log windows here. */
if (wp != w_wp) {
goto true_ret;
}
else {
Point local_pt = event -> where;
GlobalToLocal(&local_pt);
w_content( /* local_pt, event->modifiers */ );
goto false_ret;
}
case inDrag:
/* Only handle log windows here. */
if (wp != w_wp) {
goto true_ret;
}
else {
w_drag(event -> where);
goto false_ret;
}
case inGrow:
/* Only handle log windows here. */
if (wp != w_wp) {
goto true_ret;
}
else {
w_grow(event -> where);
goto false_ret;
}
case inGoAway:
/* Only handle log windows here. */
if (wp != w_wp) {
goto true_ret;
}
else {
w_goAway(event -> where);
goto false_ret;
}
case inZoomIn: case inZoomOut:
/* Only handle log windows here. */
if (wp != w_wp) {
goto true_ret;
}
else {
w_zoom(event -> where, window_type);
goto false_ret;
}
default: goto true_ret;
}
} /* End mouseDown cases */
default:
if (defaultReturn) {
goto true_ret;
}
else {
goto false_ret;
}
} /* End event->what cases. */
true_ret:
SetPort(oldPort);
return TRUE;
false_ret:
SetPort(oldPort);
return FALSE;
}
/* w_goAway: handle a mouse down event in the log window go away box. */
static void
w_goAway(Point global_pt)
{
if (TrackGoAway(w_wp, global_pt)) {
w_hide();
}
}
/* w_grow: handle a mouse down event in the log window grow box. */
static void
w_grow(Point global_pt)
{
long theResult = GrowWindow(w_wp, global_pt, &w_growRect);
if (theResult) {
/* Resize and redraw the window. */
SizeWindow(w_wp, LoWord(theResult), HiWord(theResult), 1);
/* Set the clipping region for EraseRect and DrawGrowIcon. */
ClipRect(&w_wp->portRect);
EraseRect(&w_wp->portRect);
DrawGrowIcon(w_wp);
/* Restore the clipping region. */
w_setupWindow();
/* No update event is generated if the window becomes smaller. */
w_line_update();
}
}
/* w_hide: hide the log window. */
static void
w_hide(void)
{
HideWindow(w_wp);
w_showFlag = FALSE;
}
/* w_hiliteButton: Hilite the default button in slot 1.
Do not put any Sherlock traces in this routine.
*/
static void
w_hiliteButton(DialogPtr dp)
{
Rect tempRect;
{
short DType;
Handle DItem;
GetDItem(dp, OK_ITEM, &DType, &DItem, &tempRect);
}
/* Code from Inside Macintosh I-407 (Dialog Manager.) */
PenSize(3, 3);
InsetRect(&tempRect, -4, -4);
FrameRoundRect(&tempRect, 16, 16);
PenSize(1, 1);
}
/* w_init: an explicit entry point. Called from all entry points.
Initialize the log window.
Do not put a Sherlock macro in this routine!!
This code should be called first from w_mac_init.
As a precaution, it is called from all entry points if needed.
Beep 3 times and exits if the ToolBox has not been initialized properly.
Beep 4 times and exits if the log window can't be created.
*/
static void
w_init(Boolean openFlag, char * windowName)
{
GrafPtr oldPort;
/* Allow the user to call this twice without effect. */
if (w_wInitFlag) {
return;
}
/* Beep 3 times if the ToolBox does not appear to have been initialized.
This check is not foolproof!
We will crash if the application does not initialize the ToolBox and
does not ask w_mac_init to initialize the ToolBox.
*/
if (!w_toolBoxFlag) {
SysBeep(20);
SysBeep(20);
SysBeep(20);
ExitToShell();
}
GetPort(&oldPort);
/* Remember the initial state of the window. */
w_showFlag = openFlag;
/* Allocate memory for the line buffers. */
w_wBuf = malloc(MAX_WBUF);
w_wCount = malloc(MAX_SLOTS * sizeof(int));
/* Create a window of the size specified. */
SetRect(&w_boundsRect, 3, 40, 500, 230);
CtoPstr(windowName);
w_wp = NewWindow(NULL, &w_boundsRect, (pstring) windowName,
openFlag, /* visible flag (was TRUE) */
/* documentProc */ 8, /* window definition ID. */
((WindowPtr) 0L), /* 0L: behind all: -1L in front */
TRUE, /* has go-away box. */
0L); /* no refCon field. */
PtoCstr( (pstring) windowName);
/* Beep 4 times and abort if the window could not be created. */
if (w_wp == 0L) {
SysBeep(20);
SysBeep(20);
SysBeep(20);
SysBeep(20);
ExitToShell();
}
SetPort(w_wp);
/* Set the menu bar height based on what version of ROM we are using. */
{
SysEnvRec theWorld;
if (SysEnvirons(1, &theWorld) == envNotPresent) {
/* Default to 20. */
w_MBarHeight = 20;
}
else {
/* Get value from system global. */
w_MBarHeight = GetMBarHeight();
}
}
/* Set the boundsRect for w_drag().
This only needs to be done once.
*/
SetRect(&w_dragRect,
4, w_MBarHeight + 4,
qd.screenBits.bounds.right - 4, qd.screenBits.bounds.bottom - 4);
/* Set the sizeRect for w_grow(). */
SetRect(&w_growRect,
4, w_MBarHeight + 4,
qd.screenBits.bounds.right - 4, qd.screenBits.bounds.bottom - 4);
/* Initialize the window. */
w_setupWindow();
/* Indicate that the log window system is inited. */
w_wInitFlag = TRUE;
SetPort(oldPort);
}
/* w_key: handle key events when the log window is active.
Edit command keys and normal keys are handled here.
All other command keys are passed along to the user.
Return FALSE if the user must take further action.
Do not put a Sherlock macro in this routine.
*/
static Boolean
w_key(EventRecord * event)
{
char c = event -> message & charCodeMask;
if ((event -> modifiers & cmdKey) != 0) {
return w_command(MenuKey(c));
}
else {
return FALSE;
}
}
/* w_line_insert: insert a line into the buffer, replacing the oldest line.
Long lines are silently truncated.
*/
static void
w_line_insert (char * buffer, int count)
{
/* Beep and return if the line buffer does not exists. */
if (w_wBuf == NULL || w_wCount == NULL) {
SysBeep(5);
return;
}
/* Move to the next line, slot and index */
w_wLines++;
w_wSlot++;
w_wIndex += MAX_LINE_CHARS;
if (w_wSlot >= MAX_SLOTS) {
w_wSlot = 0;
w_wIndex = 0;
}
/* Omit a trailing '\r' */
if (count < MAX_LINE_CHARS && buffer[count-1] == '\r') {
count--;
}
/* Silently truncate long lines. */
if (count >= MAX_LINE_CHARS-1) {
count = MAX_LINE_CHARS-2;
}
/* Remember the size of the line. */
w_wCount[w_wSlot] = count;
/* Copy the line to the buffer, deleting the oldest line. */
{
int i = 0;
int j = w_wIndex;
for (i = 0; i < count; i++) {
w_wBuf[j++] = buffer[i];
}
w_wBuf[j] = '\0';
}
}
/* w_line_out: output one line.
This routine works properly even if part of the
log window is hidden by another window.
*/
static void
w_line_out(void)
{
if (w_activeFlag) {
/* Draw a single line. */
if (w_wLines > w_wMaxLines || w_wLines > MAX_SLOTS) {
w_scrollWindow();
}
else {
w_curRow += w_dy;
}
/* Draw one line. */
MoveTo(LEFT_OFFSET, w_curRow);
DrawText(w_wBuf, w_wIndex, w_wCount[w_wSlot]);
}
else {
/* Redraw the whole screen.
When the log window is inactive scrolling can't be used because
ScrollRect only scrolls the visible region.
Calling w_line_update instead of ScrollRect creates a
flickering screen but I know of no way to avoid this
problem.
*/
EraseRect(&w_wp -> portRect);
w_line_update();
}
}
/* w_line_update: draw every line that should appear in the window. */
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
static void
w_line_update (void)
{
register int limit = 0;
register int slot = 0;
register int index = 0;
/* Return if no lines are in the window. */
limit = min(w_wLines, MAX_SLOTS);
limit = min(limit, w_wMaxLines);
if (limit <= 0) {
return;
}
/* Redraw as many previous lines as will fit.
w_wLines <= limit so slot will be >= 0.
*/
slot = ((w_wLines - limit) % MAX_SLOTS);
index = slot * MAX_LINE_CHARS;
/*
This routine must set w_curRow exactly like w_line_out does.
This means that w_curRow is incremented *before* calling DrawText
and the initial value must take this into account.
*/
w_curRow = w_y0 - w_dy;
{
register int i;
for (i = 0; i < limit; i++) {
/* Draw the text and set the new insertion point. */
w_curRow += w_dy;
MoveTo(LEFT_OFFSET, w_curRow);
DrawText(w_wBuf, index, w_wCount[slot]);
/* Move to the next slot. */
slot++;
index += MAX_LINE_CHARS;
if (slot >= MAX_SLOTS) {
slot = 0;
index = 0;
}
}
}
}
/* w_mac_init: an explicit entry point. Initialize the Toolbox and log window.
We will eventually crash if toolBoxFlag is set incorrectly.
However, toolBoxFlag allows us to detect other kinds of
initialization problems. In particular, w_init will beep rather
than crash if it is called before w_mac_init.
*/
void
w_mac_init
(
/* Parameters used to set global variables of the class. */
Boolean toolBoxFlag, Boolean toWindowFlag,
char * windowName, Boolean openWindowFlag,
Boolean addStdMenuFlag, Boolean addSlMenuFlag,
Boolean addAboutFlag, pstring aboutTitle,
void (*aboutCallBack)(void), Boolean menuBarFlag,
void (*eventCallBack)(void),
void (*dumpCallBack)(void), pstring userItem1,
void (*dump2CallBack)(void), pstring userItem2,
void (*dump3CallBack)(void), pstring userItem3
)
{
GrafPtr oldPort;
/* Set global variables using the parameters. */
w_windowFlag = toWindowFlag;
w_aboutFlag = addAboutFlag;
w_aboutTitle = aboutTitle;
w_stdMenuFlag = addStdMenuFlag;
w_slMenuFlag = addSlMenuFlag;
w_aboutCallBack = aboutCallBack;
w_eventCallBack = eventCallBack;
w_dumpCallBack = dumpCallBack;
w_userItem1 = userItem1;
w_dump2CallBack = dump2CallBack;
w_userItem2 = userItem2;
w_dump3CallBack = dump3CallBack;
w_userItem3 = userItem3;
/* Initialize the Macintosh toolbox. */
if (toolBoxFlag) {
/* Initialize the ToolBox routines. */
InitGraf( (Ptr) &(qd.thePort));
InitFonts();
FlushEvents(everyEvent,0);
InitWindows();
InitMenus();
TEInit();
InitDialogs(0L);
InitCursor();
}
GetPort(&oldPort);
/* Initialize the window using w_init.
Trust the user to have inited the toolbox if toolBoxFlag was FALSE.
We will crash in w_init if the application tells a lie here.
*/
w_toolBoxFlag = TRUE;
w_init(openWindowFlag, windowName);
/* Add any requested menus. */
if (!addSlMenuFlag && !addStdMenuFlag) {
/* Disable further attempts to add menus. */
w_MBarFlag = TRUE;
}
else if (menuBarFlag) {
w_drawMenuBar();
}
SetPort(oldPort);
}
/* w_menuSelect: a hidden entry point called by the MenuSelect macro.
Call the MenuSelect() Toolbox routine.
*/
long
w_menuSelect(Point pt)
{
GrafPtr oldPort;
long val = 0;
GetPort(&oldPort);
/* Initialize the log window if required. */
if (!w_wInitFlag) {
w_init(FALSE, "log");
}
SetPort(w_wp);
/* Update the menu bar. */
if (w_MBarFlag && w_slMenuFlag) {
if (log_isopen()) {
SetItem(w_menuH, W_FILE_ITEM, "\pClose File");
}
else {
SetItem(w_menuH, W_FILE_ITEM, "\pOpen File");
}
if (w_showFlag) {
SetItem(w_menuH, W_WINDOW_ITEM, "\pClose Window");
}
else {
SetItem(w_menuH, W_WINDOW_ITEM, "\pOpen Window");
}
}
/* Call the Toolbox version of Menuselect and set val. */
val = MenuSelect(pt);
if (w_command(val)) {
val = 0;
}
SetPort(oldPort);
return val;
}
/* w_pStr: print a pascal string. */
static void
w_pStr(char * s)
{
int i = *s++;
while (i--) {
echar(*s);
s++;
}
}
/* w_rawDialog: get the Sherlock arguments into w_comBuf.
Set w_windowFlag as appropriate.
Return TRUE if a file has been requested to be opened.
Do not put any Sherlock macros into this routine.
*/
#define b (qd.screenBits.bounds)
#define W_ABORT_RAW_DIALOG 7
static Boolean
w_rawDialog(
short * vRefNum, char * fileName, int max_fileName,
char * fileNamePrompt, char * defaultFileName)
{
DialogPtr dp;
GrafPtr oldPort;
Rect tempRect;
short DType;
Handle DItem;
Boolean fileFlag = FALSE;
GetPort(&oldPort);
/* Create the dialog window. */
dp = GetNewDialog(SHERLOCK_DIALOG_ID, NULL, (WindowPtr)-1);
if (dp == 0L) {
w_abort(W_ABORT_RAW_DIALOG);
}
/* Set tempRect to the portRect set by GetNewDialog. */
tempRect.top = dp -> portRect.top;
tempRect.left = dp -> portRect.left;
tempRect.bottom = dp -> portRect.bottom;
tempRect.right = dp -> portRect.right;
tempRect.top = ((b.bottom-b.top) - (tempRect.bottom-tempRect.top)) / 2;
tempRect.left = ((b.right-b.left) - (tempRect.right-tempRect.left)) / 2;
/* Draw the dialog window. */
MoveWindow(dp, tempRect.left, tempRect.top, TRUE);
ShowWindow(dp);
SelectWindow(dp);
SetPort(dp);
/* Set the characteristics of the text. */
{
TEHandle d_TEH = ((DialogPeek) dp) -> textH;
HLock( (Handle) d_TEH);
(*d_TEH) -> txSize = 12;
TextSize(12);
(*d_TEH) -> txFont = systemFont;
TextFont(systemFont);
(*d_TEH) -> fontAscent = 12;
(*d_TEH) -> lineHeight = 12 + 3 + 1;
HUnlock( (Handle) d_TEH);
}
/* Initialize the dialog. */
GetDItem(dp,SHERLOCK_ARGS_ITEM, &DType, &DItem, &tempRect);
SetIText(DItem, "\p");
w_hiliteButton(dp);
/* Handle all dialog events. */
for(;;) {
short itemHit;
/* Get the next dialog event. */
ModalDialog(NULL, &itemHit);
GetDItem(dp, itemHit, &DType, &DItem, &tempRect);
if (itemHit == OK_ITEM ) {
/* Handle it real time */
break;
}
if (itemHit == CANCEL_ITEM) {
/* Restore the default settings. */
fileFlag = FALSE;
break;
}
if (itemHit == TO_DISK_FILE_ITEM ) {
fileFlag = !fileFlag;
SetCtlValue( ((ControlHandle) DItem), fileFlag);
if (fileFlag) {
fileFlag = w_std_file_dialog(vRefNum, fileName, max_fileName,
fileNamePrompt, defaultFileName);
SetCtlValue( ((ControlHandle) DItem), fileFlag);
w_hiliteButton(dp);
/* 12/6/90 */
slw_update();
}
}
}
/* Get the arguments into w_comBuf */
GetDItem(dp,SHERLOCK_ARGS_ITEM, &DType, &DItem, &tempRect);
GetIText(DItem, &w_comBuf[0]);
PtoCstr((pstring) &w_comBuf[0]);
/* Dismiss the dialog box. */
DisposDialog(dp);
SetPort(oldPort);
slw_update();
return fileFlag;
}
#undef b
/* w_scrollWindow: scroll the log window by calling ScrollRect.
ScrollRect will not work properly if the log window is covered
since its visRgn will not include the whole window.
*/
static void
w_scrollWindow(void)
{
RgnHandle rH = NewRgn();
ScrollRect(&w_clipRect, 0, -w_dy, rH);
DisposeRgn(rH);
}
/* w_setupWindow: Set the globals describing the log window. */
static void
w_setupWindow(void)
{
FontInfo info;
/* Set w_y0, w_dy, and w_y0 to describe the window's font. */
TextFont(4); /* Specify Monaco 9. */
TextSize(9);
GetFontInfo(&info);
w_height = info.ascent;
w_dy = info.ascent + info.descent + info.leading + EXTRA_LEADING;
w_y0 = w_height + TOP_CLIP;
/* Set w_maxRow. It is used only to set the clipping and scrolling regions. */
w_maxRow = (w_wp -> portRect.bottom - w_wp -> portRect.top)
- SBarWidth - BOTTOM_CLIP;
/* Set w_wMaxLines and w_curRow.
The first line of text will be positioned at w_y0.
Count 1 for that row plus rows/w_dy.
Reserve rows for the descender on the last line.
*/
{
int rows = w_maxRow - w_y0 - info.descent;
w_wMaxLines = 1 + (rows/w_dy);
}
/* Allow for pre-increment of w_dy in sl_out_line. */
w_curRow = w_y0 - w_dy;
/* Set w_clipRect and call ClipRect. */
SetRect(&w_clipRect,
w_wp -> portRect.left,
w_wp -> portRect.top + TOP_CLIP,
w_wp -> portRect.right -SBarWidth - RIGHT_CLIP,
w_wp -> portRect.top + w_maxRow);
ClipRect(&w_clipRect);
}
/* w_show: show the log window. */
static void
w_show(void)
{
ShowWindow(w_wp);
w_showFlag = TRUE;
slw_update();
}
/* w_std_file_dialog: Get a file name (for write access) into fileName.
Get a volume number into vRefNum.
Return TRUE if all is well.
*/
static int
w_std_file_dialog(
short * vRefNum,
char * fileName,
int max_fileName,
char * fileNamePrompt,
char * defaultFileName)
{
SFReply reply;
/* Get the file name, using a Standard File Dialog. */
CtoPstr(defaultFileName);
CtoPstr(fileNamePrompt);
{
Point upper_left;
upper_left.h = 100;
upper_left.v = 50;
SFPutFile(
upper_left, /* Corner of dialog. */
(pstring) fileNamePrompt, /* Prompt string. */
(pstring) defaultFileName, /* Default file name. */
NULL, /* dlgHook field. */
&reply); /* reply record. */
}
PtoCstr((pstring) defaultFileName);
PtoCstr((pstring) fileNamePrompt);
/* Redraw the screen after the Standard File Dialog has been dismissed. */
slw_update();
if (reply.good) {
/* Set fileName and vRefNum. Return FALSE if the file name is bad. */
/* The maximum length of the file name is 63 characters. */
PtoCstr( (pstring) &reply.fName);
/* 3/21/91 */
if (strlen((char *) &reply.fName) < max_fileName) {
strcpy(fileName, (char *) &reply.fName);
}
else {
return FALSE;
}
/* Check for null file name. */
if (fileName[0] == '\0') {
return FALSE;
}
*vRefNum = reply.vRefNum;
return TRUE;
}
else {
return FALSE;
}
}
/* slw_update: an explicit entry point.
Redraw the log window in response to an update event.
*/
void
slw_update(void)
{
GrafPtr oldPort;
GetPort(&oldPort);
/* Initialize the log window if required. */
if (!w_wInitFlag) {
w_init(FALSE, "log");
}
/* Redraw the screen.
The advantage of putting as much code as possible between
BeginUpdate and EndUpdate is that only those operations on
the update region are actually drawn.
*/
SetPort(w_wp);
BeginUpdate(w_wp);
/* Expand the clipping region. */
w_setupWindow();
ClipRect(&w_wp->portRect);
EraseRect(&w_wp->portRect);
DrawGrowIcon(w_wp);
/* Contract the clipping region. */
w_setupWindow();
w_line_update();
EndUpdate(w_wp);
SetPort(oldPort);
}
/* w_write: an explicit entry point. Write a line to the window. */
void
slw_write(char * buffer, int count)
{
GrafPtr oldPort;
GetPort(&oldPort);
/* Open the window so we can be alerted if something happens. */
if (!w_wInitFlag) {
w_init(TRUE, "log");
}
SetPort(w_wp);
/* Write the line to the window. */
if (w_windowFlag) {
/* Make the weird Mac conversion from '\n' to '\r' */
if (count > 0 && buffer[count-1] == '\n') {
buffer[count-1] = '\r';
}
w_line_insert(buffer, count);
w_line_out();
}
/* Allow a break by invoking the event callback routine. */
if (w_eventCallBack != 0L) {
(*w_eventCallBack)();
}
SetPort(oldPort);
}
/* w_zoom: zoom the log window in or out. */
static void
w_zoom(Point global_pt, int zoomCode)
{
if(TrackBox(w_wp, global_pt, zoomCode)) {
ZoomWindow(w_wp, zoomCode, FALSE);
/* Set the clipping region for DrawGrowIcon. */
ClipRect(&w_wp->portRect);
EraseRect(&w_wp->portRect);
DrawGrowIcon(w_wp);
w_setupWindow();
w_line_update();
}
}